﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Kugar.Core.ExtMethod;

namespace Kugar.UI.WinForm
{
    /// <summary>
    ///     根据Value属性的值类型不同,显示相应的控件
    /// </summary>
    /// <remarks>
    ///     如果需要增加不同的值类型对应控件,建议继承本控件,重载相应的函数
    /// </remarks>
    public class DynamicValueBox : Panel,INotifyPropertyChanged
    {
        protected Dictionary<Type, Control> _cacheControl = new Dictionary<Type, Control>();
        //private object _value = null;
        private Control _control = null;
        private Label _nullValueLabel=new Label(){Text = ""};

        public DynamicValueBox()
        {
            DefaultDatetimePickerConfig=new DatetimePickerConfig();
            DefaultTextBoxConfig = new TextBoxConfig();
            DefaultNumericUpDownConfig=new NumericUpDownConfig();
            DefaultPictureBoxConfig=new PictureBoxConfig();
            NullValue = "";
            Value = null;
            
        }

        public object Value
        {
            get
            {
                return getControlValue(_control);
            }
            set
            {
                if (value == null)
                {
                    refreshValueDisplay(NullValue);
                    OnPropertyChanged("Value");
                    return;
                }

                var _value = getControlValue(_control);

                if ((value!=null && !value.Equals(_value)) || (value==null && _value!=null))
                {
                    refreshValueDisplay(value);
                    OnPropertyChanged("Value");
                }

            }
        }

        public Control CurrentControl { get { return _control; } }

        public object NullValue { set; get; }

        /// <summary>
        ///     默认日期编辑控件的设置
        /// </summary>
        public DatetimePickerConfig DefaultDatetimePickerConfig { get; private set; }
        public TextBoxConfig DefaultTextBoxConfig { get;private set; }
        public NumericUpDownConfig DefaultNumericUpDownConfig { get; private set; }
        public PictureBoxConfig DefaultPictureBoxConfig { get; private set; }

        public event EventHandler<ControlShowingEventArgs> ControlShowed;
        public event EventHandler<CustonValueControlEventArgs> CustonValueControl;
        public event EventHandler<CustonValueControlEventArgs> GetCustomControlValue;
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        ///     刷新指定值的控件显示
        /// </summary>
        /// <param name="value"></param>
        protected virtual void refreshValueDisplay(object value)
        {
            this.Controls.Remove(_control);

            if (CustonValueControl != null)
            {
                _control = OnCustonValueControl(value);
            }
            else
            {
                if (Value == null)
                {
                    _control = _nullValueLabel;
                }
                else
                {
                    _control = getControlByValue(value);

                    setControlValue(_control, value);

                    OnControlShowed(_control);
                }
            }

            if (_control!=null)
            {
                _control.Dock = DockStyle.Fill;
                _control.Enabled = this.Enabled;
                this.Controls.Add(_control);
            }
        }

        /// <summary>
        /// 将值设置到控件中
        /// </summary>
        /// <param name="ctrl"></param>
        /// <param name="value"></param>
        protected virtual void setControlValue(Control ctrl, object value)
        {
            if (value is DBNull)
            {
                value = null;
            }

            if (ctrl is PictureBox)
            {
                this.DefaultPictureBoxConfig.SetConfigValue(ctrl);
                ((PictureBox) ctrl).Image = (Image) value;

            }
            else if(ctrl is DateTimePicker)
            {
                this.DefaultDatetimePickerConfig.SetConfigValue(ctrl);
                ((DateTimePicker) ctrl).Value = (DateTime) value;

            }
            else if(ctrl is TextBox)
            {
                this.DefaultTextBoxConfig.SetConfigValue(ctrl);
                ((TextBox) ctrl).Text = (string) value;

            }
            else if(ctrl is NumericUpDown)
            {
                this.DefaultNumericUpDownConfig.SetConfigValue(ctrl);
                ((NumericUpDown)ctrl).Value = (decimal)Convert.ChangeType(value, typeof(decimal));

            }
            else if(ctrl is Label)
            {
                ((Label) ctrl).Text = value.ToStringEx();
            }
        }

        /// <summary>
        ///     获取当前显示中的控件的值
        /// </summary>
        /// <param name="ctrl">指定的控件</param>
        /// <returns></returns>
        protected virtual object getControlValue(Control ctrl)
        {
            if (ctrl == null)
            {
                return null;
            }

            if (ctrl is PictureBox)
            {
                return ((PictureBox)ctrl).Image;
            }
            else if (ctrl is DateTimePicker)
            {
                return  ((DateTimePicker)ctrl).Value;
            }
            else if (ctrl is TextBox)
            {
               return ((TextBox)ctrl).Text;

            }
            else if (ctrl is NumericUpDown)
            {
                return ((NumericUpDown)ctrl).Value ;

            }
            else if (ctrl is Label)
            {
                return ((Label)ctrl).Text;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        ///     根据传入值,返回对应的控件
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        protected virtual Control getControlByValue(object value)
        {
            Control ctrl = null;

            var type = value.GetType();

            bool isNew = false;

            if (_cacheControl.TryGetValue(type,out ctrl))
            {
                return ctrl;
            }
            else
            {
                if (type == typeof(Image))
                {
                    ctrl = new PictureBox();
                    
                    this.DefaultPictureBoxConfig.SetConfigValue(ctrl);
                }
                else if (type == typeof(string))
                {
                    var txt=new TextBox();
                    ctrl = txt;
                    txt.TextChanged += onControlValueChange;
                    this.DefaultTextBoxConfig.SetConfigValue(ctrl);
                }
                else if ( type == typeof(int) || 
                            type == typeof(uint) || 
                            type == typeof(long) || 
                            type == typeof(ulong) || 
                            type == typeof(short) || 
                            type == typeof(ushort) || 
                            type == typeof(double) || 
                            type == typeof(float) || 
                            type == typeof(decimal)
                    )
                {
                    var num=new NumericUpDown();
                    ctrl = num;
                    num.ValueChanged += onControlValueChange;
                    this.DefaultNumericUpDownConfig.SetConfigValue(ctrl);
                }
                else if(type == typeof(DateTime))
                {
                    var dt=new DateTimePicker();
                    ctrl = dt;
                    dt.ValueChanged += onControlValueChange;
                    this.DefaultDatetimePickerConfig.SetConfigValue(ctrl);
                }
                else
                {
                    if (CustonValueControl!=null)
                    {
                        ctrl=OnCustonValueControl(value);
                    }

                    if (ctrl==null)
                    {
                        ctrl = new Label();
                    }
                }

                _cacheControl.Add(type,ctrl);
            }

            return ctrl;
        }


        //响应控件在界面上编辑后的修改事件
        void onControlValueChange(object sender, EventArgs e)
        {
            OnPropertyChanged("Value");
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

        protected virtual Control OnCustonValueControl(object value)
        {
            if (CustonValueControl!=null)
            {
                var e = new CustonValueControlEventArgs(value);

                CustonValueControl(this, e);

                return e.Ctrl;
            }
            else
            {
                return null;
            }


            

        }

        protected virtual void  OnControlShowed(Control ctrl)
        {
            if (ControlShowed!=null)
            {
                var e = new ControlShowingEventArgs(ctrl);

                ControlShowed(this, e);
            }
        }
    }


    public interface IControlStyleSetter
    {
        void SetConfigValue(Control ctrl);
    }

    public class ControlShowingEventArgs:EventArgs
    {
        public ControlShowingEventArgs(Control ctrl)
        {
            Ctrl = ctrl;
        }

        public Control Ctrl { get; private set; }
    }

    public class CustonValueControlEventArgs:EventArgs
    {
        public CustonValueControlEventArgs(object value)
        {
            Value = value;
        }

        public Control Ctrl { get; private set; }

        public object Value {private set; get; }
    }


    public class DatetimePickerConfig : IControlStyleSetter
    {
        public DatetimePickerConfig()
        {

        }

        public string CustomFormat { set; get; }
        public DateTimePickerFormat Format { set; get; }


        public void SetConfigValue(Control ctrl)
        {
            var dp = (DateTimePicker) ctrl;

            dp.Format = Format;
            dp.CustomFormat = this.CustomFormat;
        }
    }


    public class TextBoxConfig : IControlStyleSetter
    {
        public TextBoxConfig()
        {
            this.TextAlign = HorizontalAlignment.Left;
            this.Multiline = false;
        }

        public HorizontalAlignment TextAlign { set; get; }
        public bool Multiline { set; get; }

        #region Implementation of IControlStyleSetter

        public void SetConfigValue(Control ctrl)
        {
            var txt = (TextBox) ctrl;

            txt.TextAlign = this.TextAlign;
            txt.Multiline = this.Multiline;
        }

        #endregion
    }

    public class NumericUpDownConfig : IControlStyleSetter
    {
        public NumericUpDownConfig()
        {
            DecimalPlaces = 4;
            Maximum = decimal.MaxValue;
            Minimum = decimal.MinValue;
        }


        public int DecimalPlaces;
        public decimal Maximum;
        public decimal Minimum;

        #region Implementation of IControlStyleSetter

        public void SetConfigValue(Control ctrl)
        {
            var num = (NumericUpDown) ctrl;

            num.Maximum = this.Maximum;
            num.Minimum = this.Minimum;
            num.DecimalPlaces = this.DecimalPlaces;
        }

        #endregion
    }

    public class PictureBoxConfig : IControlStyleSetter
    {
        public PictureBoxConfig()
        {
            this.SizeMode = PictureBoxSizeMode.StretchImage;
        }

        public Image ErrorImage { set; get; }

        public PictureBoxSizeMode SizeMode { set; get; }

        #region Implementation of IControlStyleSetter

        public void SetConfigValue(Control ctrl)
        {
            var pic = (PictureBox) ctrl;
            pic.ErrorImage = this.ErrorImage;
            pic.SizeMode = this.SizeMode;
        }

        #endregion
    }
}
